package com.atguigu.service.impl;

import com.atguigu.client.ProductFeignClient;
import com.atguigu.constant.RedisConst;
import com.atguigu.entity.CartInfo;
import com.atguigu.entity.SkuInfo;
import com.atguigu.mapper.CartInfoMapper;
import com.atguigu.service.AsyncCartInfoService;
import com.atguigu.service.CartInfoService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * <p>
 * 购物车表 用户登录系统时更新冗余 服务实现类
 * </p>
 *
 * @author zhufeiyu
 * @since 2022-01-18
 */
@Service
public class CartInfoServiceImpl extends ServiceImpl<CartInfoMapper, CartInfo> implements CartInfoService {

    @Autowired
    private ProductFeignClient productFeignClient;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private AsyncCartInfoService asyncCartInfoService;

    //1.商品添加到购物车
    @Override
    public void addToCart(String oneOfUserId, Long skuId, Integer skuNum) {
        //a.先查询数据库中是否有该商品信息
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", oneOfUserId);
        wrapper.eq("sku_id", skuId);
        CartInfo existCartInfo = baseMapper.selectOne(wrapper);
        //去查到商品的实时价格(数据库)
        BigDecimal realTimePrice = productFeignClient.getSkuPrice(skuId);
        //如果有
        if (existCartInfo != null) {
            //对商品数量进行操作 直接添加
            existCartInfo.setSkuNum(existCartInfo.getSkuNum() + skuNum);
            //设置实时价格 数据库
            existCartInfo.setRealTimePrice(realTimePrice);
            //更新数据库
//            baseMapper.updateById(existCartInfo);
            asyncCartInfoService.updateCartInfo(existCartInfo);
        } else {
            existCartInfo = new CartInfo();
            existCartInfo.setUserId(oneOfUserId);
            existCartInfo.setSkuId(skuId);
            existCartInfo.setSkuNum(skuNum);

            SkuInfo skuInfo = productFeignClient.getSkuInfo(skuId);
            existCartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            existCartInfo.setSkuName(skuInfo.getSkuName());

            //从缓存中获取的价格
            existCartInfo.setCartPrice(skuInfo.getPrice());
            //设置商品实时价格
            existCartInfo.setRealTimePrice(realTimePrice);

            //商品默认勾选了
            existCartInfo.setIsChecked(1);

//            baseMapper.insert(existCartInfo);
            asyncCartInfoService.insertCartInfo(existCartInfo);
        }
        //b.还需要把数据添加到redis当中  user:userId:cart
        String userKey = getUserKey(oneOfUserId);
        redisTemplate.boundHashOps(userKey).put(skuId.toString(), existCartInfo);
        setCartKeyExpire(userKey);
    }

    //设置购物车过期时间
    private Boolean setCartKeyExpire(String userKey) {
        return redisTemplate.expire(userKey, RedisConst.USERKEY_TIMEOUT, TimeUnit.SECONDS);
    }

    //得到购物车缓存的名称
    private String getUserKey(String oneOfUserId) {
        return RedisConst.USER_KEY_PREFIX + oneOfUserId + RedisConst.USER_CART_KEY_SUFFIX;
    }

    //2.购物车列表信息
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {
        List<CartInfo> noLoginCartInfoList = new ArrayList<>();
        //1.当用户未登录
        if (!StringUtils.isEmpty(userTempId)) {
            noLoginCartInfoList = getUserCartList(userTempId);
        }
        //2.当用户登录了
        if (!StringUtils.isEmpty(userId)) {
            //查询未登录的
            if (!CollectionUtils.isEmpty(noLoginCartInfoList)) {
                //需要对其进行合并
                List<CartInfo> cartInfoList = mergeCartInfoList(noLoginCartInfoList, userId);
                //合并之后需要删除未登录的购物车信息
                deleteCartInfoList(userTempId,null);
                return cartInfoList;
            } else {
                List<CartInfo> cartInfoList = getUserCartList(userId);
                return cartInfoList;
            }
        }
        return noLoginCartInfoList;
    }

    //3.商品的选中状态
    @Override
    public void checkCart(String oneOfUserId, Long skuId, Integer isChecked) {
        //a.操作redis里面的选中状态
        String userKey = getUserKey(oneOfUserId);
        BoundHashOperations boundHash = redisTemplate.boundHashOps(userKey);
        //看redis中是否有该商品的信息
        if (boundHash.hasKey(skuId.toString())) {
            CartInfo redisCartInfo = (CartInfo) boundHash.get(skuId.toString());
            redisCartInfo.setIsChecked(isChecked);
            //更新到redis
            boundHash.put(skuId.toString(), redisCartInfo);
            //设置过期时间
            setCartKeyExpire(userKey);
        }
        //b.在数据库中修改状态
        asyncCartInfoService.checkDbCart(oneOfUserId, skuId, isChecked);
    }

    //4.购物车商品的删除
    @Override
    public void deleteCart(Long skuId, String oneOfUserId) {
        //a.删除redis当中商品
        String userKey = getUserKey(oneOfUserId);
        BoundHashOperations boundHash = redisTemplate.boundHashOps(userKey);
        //看redis中是否有该商品的信息
        if (boundHash.hasKey(skuId.toString())) {
            boundHash.delete(skuId.toString());
        }
        //b.删除数据库中的购物信息
        deleteCartInfoList(oneOfUserId, skuId);
    }


    private void checkDbCart(String oneOfUserId, Long skuId, Integer isChecked) {
        /**
         * 根据条件进行修改
         * update cart_info set is_checked = 0 where user_id = xxx and sku_id = xxx
         */
        CartInfo cartInfo = new CartInfo();
        cartInfo.setIsChecked(isChecked);
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", oneOfUserId);
        wrapper.eq("sku_id", skuId);
        baseMapper.update(cartInfo, wrapper);
    }

    private void deleteCartInfoList(String userTempId, Long skuId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        if (!StringUtils.isEmpty(userTempId)) {
            wrapper.eq("user_id", userTempId);
        }
        if (!StringUtils.isEmpty(skuId)) {
            wrapper.eq("sku_id", skuId);
        }
        baseMapper.delete(wrapper);
    }

    private List<CartInfo> mergeCartInfoList(List<CartInfo> noLoginCartInfoList, String userId) {
        //a.取出未登录和已登录购物车信息
        List<CartInfo> loginUserCartList = getUserCartList(userId);
        Map<Long, CartInfo> cartInfoMap = loginUserCartList.stream().collect(Collectors.toMap(CartInfo::getSkuId, cartInfo -> cartInfo));
        for (CartInfo noLoginCartInfo : noLoginCartInfoList) {
            Long skuId = noLoginCartInfo.getSkuId();
            //b.迭代对比skuId是否相同
            if (cartInfoMap.containsKey(skuId)) {
                //sku数量相加
                CartInfo loginCartInfo = cartInfoMap.get(skuId);
                loginCartInfo.setSkuNum(loginCartInfo.getSkuNum() + noLoginCartInfo.getSkuNum());
                //当未登录的时候勾选装填决定合并之后的状态
                if (noLoginCartInfo.getIsChecked() == 1) {
                    loginCartInfo.setIsChecked(1);
                }
//                baseMapper.updateById(loginCartInfo);
                asyncCartInfoService.updateCartInfo(loginCartInfo);
            } else {
                //把临时用户id改为登录用户id
                noLoginCartInfo.setUserId(userId);
//                baseMapper.updateById(noLoginCartInfo);
                asyncCartInfoService.updateCartInfo(noLoginCartInfo);
            }
        }
        //c.合并之后需要重新查一下数据库
        List<CartInfo> cartInfoList = queryFromDbToRedis(userId);
        return cartInfoList;
    }

    private List<CartInfo> getUserCartList(String oneOfUserId) {
        return queryFromDbToRedis(oneOfUserId);
    }

    //6.从数据库中查询最新的购物车信息到redis中
    @Override
    public List<CartInfo> queryFromDbToRedis(String oneOfUserId) {
        QueryWrapper<CartInfo> wrapper = new QueryWrapper<>();
        wrapper.eq("user_id", oneOfUserId);
        List<CartInfo> dbCartInfoList = baseMapper.selectList(wrapper);
        //如果数据库中不存在用户添加过的购物车信息
        if (CollectionUtils.isEmpty(dbCartInfoList)) {
            return dbCartInfoList;
        }
        String userCartKey = getUserKey(oneOfUserId);
        HashMap<String, CartInfo> cartInfoMap = new HashMap<>();
        //如果数据库中不为空,此时需要把最新购物车信息添加到redis中
        for (CartInfo cartInfo : dbCartInfoList) {
            //商家可能会更改价格,所以需要获取实时价格,再添加到缓存
            cartInfo.setRealTimePrice(productFeignClient.getSkuPrice(cartInfo.getSkuId()));
//            redisTemplate.boundHashOps(userCartKey).put(cartInfo.getSkuId().toString(),cartInfo);
            cartInfoMap.put(cartInfo.getSkuId().toString(), cartInfo);
        }
        redisTemplate.opsForHash().putAll(userCartKey, cartInfoMap);
        setCartKeyExpire(userCartKey);
        return dbCartInfoList;
    }

    //5.查询选中的商品信息---送货清单
    @Override
    public List<CartInfo> getSelectedProduct(String userId) {
        ArrayList<CartInfo> retCartInfo = new ArrayList<>();
        String userKey = getUserKey(userId);
        List<CartInfo> cartInfoList = redisTemplate.opsForHash().values(userKey);
        if (!CollectionUtils.isEmpty(cartInfoList)) {
            for (CartInfo cartInfo : cartInfoList) {
                //拿到勾选了的商品信息
                if (cartInfo.getIsChecked() == 1) {
                    retCartInfo.add(cartInfo);
                }
            }
        }
        return retCartInfo;
    }
}
